﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

namespace Neto.Web;

/// <summary>
///     文件上传
/// </summary>
public class WebUpload
{
    /// <summary>
    ///     获取当前语种名称代码，如果没获取到，默认:zh-CN
    /// </summary>
    /// <returns></returns>
    private static string GetSelectCultureCode => L.GetSelectCulture()?.Culture?.Name ?? "zh-CN";
    // //原子递增计数器
    // private static long _counter;

    /// <summary>
    ///     上传单个文件。
    /// </summary>
    /// <param name="uploadConfig">上传配置。</param>
    /// <param name="file">要上传的文件，为可选参数，默认为null。如果未指定，将从HTTP请求中获取文件。</param>
    /// <returns>上传结果。</returns>
    public static async Task<WebUploadResult> UploadFile(WebUploadConfig uploadConfig,
        IFormFile? file = null
    )
    {
        if (file == null)
        {
            // 尝试从HTTP上下文中获取文件
            var context = App.HttpContext;
            if (context?.Request.Form.Files is not { Count: > 0 })
                // 如果没有找到文件，抛出异常
                ThrowNoSelectFileError();

            file = context?.Request.Form.Files[0];
        }

        // 检查所选文件的长度是否小于0
        if (file?.Length < 0) ThrowNoSelectFileError();

        var uploadResult = await FileUploadItem(uploadConfig, file);
        return uploadResult;
    }

    /// <summary>
    ///     上传多个文件。
    /// </summary>
    /// <param name="uploadConfig">上传配置。</param>
    /// <param name="files">要上传的文件列表，为可选参数，默认为null。如果未指定，将从HTTP请求中获取文件。</param>
    /// <param name="fileVer">文件验证函数，为可选参数，默认为null。用于在上传前验证文件。</param>
    /// <returns>上传结果列表。</returns>
    public static async Task<List<WebUploadResult>> UploadFiles(WebUploadConfig uploadConfig,
        List<IFormFile?>? files = null
    )
    {
        // 尝试从HTTP上下文中获取附加的文件
        var context = App.HttpContext;
        if (context?.Request.Form.Files is { Count: > 0 })
        {
            files ??= [];
            files.AddRange(context.Request.Form.Files);
        }

        // 如果没有文件准备上传，抛出异常
        if (files == null || files.Count == 0) ThrowNoSelectFileError();

        var uploadResults = new List<WebUploadResult>();
        foreach (var file in files.OfType<IFormFile>())
        {
            // 检查所选文件的长度是否小于0
            if (file.Length < 0) continue;
            var uploadResult = await FileUploadItem(uploadConfig, file);
            uploadResults.Add(uploadResult);
        }

        return uploadResults;
    }

    /// <summary>
    ///     抛出没有选择上传文件错误
    /// </summary>
    /// <exception cref="AppFriendlyException"></exception>
    private static void ThrowNoSelectFileError()
    {
        var message = GetSelectCultureCode == "en-US"
            ? "Please select the file to be uploaded!"
            : "请选择上传的文件!";
        throw Oops.Bah(message);
    }


    /// <summary>
    ///     单文件上传
    /// </summary>
    /// <param name="uploadConfig">上传文件配置</param>
    /// <param name="file">上传的文件</param>
    /// <returns></returns>
    private static async Task<WebUploadResult> FileUploadItem(WebUploadConfig uploadConfig, IFormFile file)
    {
        var uploadResult = new WebUploadResult(uploadConfig);

        try
        {
            uploadResult.UploadFilename = file.FileName;
            //获取上传文件扩展名
            uploadResult.Extension = file.FileName.GetExtension().ToLower();

            #region 判断大小

            //imgFile.Length (单位字节)
            var maxlength = uploadConfig.MaxFileSize * 1024 * 1024; //转换为字节
            var mb = file.Length / 1024 / 1024; // MB
            if (file.Length > maxlength)
            {
                //判断当前语种代码
                if (GetSelectCultureCode == "en-US")
                    //Upload files over 10MB
                    throw Oops.Bah($"Upload files over {uploadConfig.MaxFileSize}MB");
                throw Oops.Bah($"上传文件超过{uploadConfig.MaxFileSize}MB");
            }

            uploadResult.FileSize_Byte = file.Length; //字节
            uploadResult.FileSize_MB = ByteSizeFormatter.FormatBytes(file.Length, ByteUnit.MB, 1);

            #endregion 判断大小

            #region 验证上传的文件扩展名是否是允许上传的

            if (uploadConfig.AllowExtensions == null || uploadConfig.AllowExtensions.Count == 0)
                uploadConfig.AllowExtensions = new List<string>
                {
                    ".jpg",
                    ".jpeg",
                    ".png",
                    ".gif",
                    ".doc",
                    ".docx",
                    ".xls",
                    ".xlsx",
                    ".pdf"
                };

            if (!uploadConfig.AllowExtensions?.Contains(uploadResult.Extension, StringComparer.OrdinalIgnoreCase) ??
                false)
            {
                //The file upload format is incorrect, only the .png format file or image is allowed to be uploaded!
                //$"文件上传格式错误，只允许上传{input.Options.AllowExtensions.ToString(",")}格式的文件或图片！"
                if (GetSelectCultureCode == "en-US")
                    throw Oops.Bah(
                        $"he file upload format is incorrect, only the {uploadConfig.AllowExtensions?.ToString(",")} format file or image is allowed to be uploaded!");
                throw Oops.Bah($"文件上传格式错误，只允许上传{uploadConfig.AllowExtensions?.ToString(",")}格式的文件或图片！");
            }

            #endregion

            #region 验证文件头

            {
                if (uploadConfig.NoVerFileHeaderExtensions != null &&
                    uploadResult.Extension != null &&
                    uploadConfig.NoVerFileHeaderExtensions.Contains(uploadResult.Extension,
                        StringComparer.OrdinalIgnoreCase))
                {
                    //什么都不做，在不验证文件头的扩展名中
                }
                else
                {
                    using var memoryStream = new MemoryStream();
                    // 将文件流复制到内存流中以便读取文件头信息
                    await file.OpenReadStream().CopyToAsync(memoryStream);
                    //var fileBytes = memoryStream.ToArray();
                    var fileHeaderCheckResult =
                        FileHeaderCheckHelper.UploadFileHeaderCheckResult(memoryStream, uploadResult.Extension);
                    // if (fileHeaderCheckResult.IsSuccess)
                    // {
                    if (fileHeaderCheckResult.State is FileHeaderCheckState.错误 or FileHeaderCheckState.失败)
                    {
                        //判断当前语种代码
                        if (GetSelectCultureCode == "en-US")
                            throw Oops.Bah("File upload format error, please upload the correct file!");
                        throw Oops.Bah("文件上传格式错误，请上传正确的文件!");
                    }

                    if (fileHeaderCheckResult.State == FileHeaderCheckState.未找到验证规则)
                        //如果没找到验证规则，则调用自定义验证方法
                        if (uploadConfig.FileVer != null)
                            //文件验证失败
                            //throw Oops.Bah("File validation failed");
                            uploadResult.IsCustomerVerSuccess =
                                uploadConfig.FileVer.Invoke(uploadConfig, uploadResult, file);
                }
                //}
            }

            #endregion

            // 获取新文件名
            uploadResult.NewFilename = GetFileNewName(uploadConfig, uploadResult.Extension, uploadResult.FId);
            // 获取相对文件夹路径
            uploadResult.RelFileFloder = GetRelFileFloder(uploadConfig);
            //获取相对路径+文件名
            uploadResult.RelFilePath =
                GetRelFileName(uploadConfig, uploadResult.RelFileFloder, uploadResult.NewFilename);
            //获取文件路径
            uploadResult.FullNewFilePath = GetFullFilePath(uploadConfig, uploadResult.RelFilePath);

            // 使用文件流创建文件并异步复制文件内容
            await using (var fs = File.Create(uploadResult.FullNewFilePath)) // 创建文件流，准备写入文件
            {
                await file.CopyToAsync(fs); // 异步将文件内容复制到创建的文件流中
                fs.Flush(); // 刷新文件流，确保内容被写入磁盘
            }

            // //是否图片验证：默认验证：文件格式有：JPEG、PNG、GIF、BMP、TIFF、WebP
            // //只有设置的扩展名在 VerImageExtensions 列表中才会验证图片，否则不验证
            // if (uploadConfig.IsVerImage &&
            //     (uploadConfig.VerImageExtensions?.Contains(uploadResult.Extension, StringComparer.OrdinalIgnoreCase) ??
            //      false))
            // {
            //     uploadResult.IsVerImageSuccess = FileHelper.IsImageFileByHeader(uploadResult.FullNewFilePath);
            //     if (uploadResult.IsVerImageSuccess == false) throw Oops.Bah("File validation failed");
            // }


            //图片压缩方法
            ImgCompress(uploadConfig, uploadResult);
            //生成图片缩略图
            ImgThumbnail(uploadConfig, uploadResult);

            var context = App.HttpContext;

            //默认返回：/f/文件ID
            uploadResult.HttpRelSrc = HandlePathOrUrl($"/{uploadConfig.RelRoutUrl.Trim('/')}/{uploadResult.FId}");

            //默认返回：http://域名/f/文件ID
            uploadResult.HttpFullSrc = context?.GetDomain()?.TrimEnd('/') + "/" +
                                       HandlePathOrUrl($"{uploadConfig.RelRoutUrl.Trim('/')}/{uploadResult.FId}");

            uploadResult.Success = true; //表示上传成功了
        }
        catch (Exception e)
        {
            // Console.WriteLine(e);
            // throw;
            uploadResult.Error = e.Message;

            LogX.Error($"上传配置：{uploadConfig.ToJson()}\r\n返回结果：{uploadResult.ToJson()}\r\n异常信息：{e.ToStringEx()}",
                "Upload");
            throw;
        }

        return uploadResult;
    }

    private static string DetectMimeType(byte[] bytes)
    {
        if (IsPdf(bytes)) return "application/pdf";
        if (IsOpenXml(bytes)) return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        if (IsJpeg(bytes)) return "image/jpeg";
        if (IsPng(bytes)) return "image/png";
        if (IsGif(bytes)) return "image/gif";
        if (IsWebp(bytes)) return "image/webp";
        if (IsZip(bytes)) return "application/zip";
        if (Is7z(bytes)) return "application/x-7z-compressed";
        if (IsRar(bytes)) return "application/x-rar-compressed";
        if (IsTxt(bytes)) return "text/plain";
        if (IsCss(bytes)) return "text/css";
        return "application/octet-stream";
    }

    private static bool IsPdf(byte[] bytes)
    {
        return bytes.Length >= 4 && bytes[0] == 0x25 && bytes[1] == 0x50 &&
               bytes[2] == 0x44 && bytes[3] == 0x46;
    }

    private static bool IsOpenXml(byte[] bytes)
    {
        return bytes.Length >= 8 && bytes[0] == 0x50 && bytes[1] == 0x4B &&
               bytes[2] == 0x03 && bytes[3] == 0x04;
    }

    private static bool IsJpeg(byte[] bytes)
    {
        return bytes.Length >= 2 && bytes[0] == 0xFF && bytes[1] == 0xD8;
    }

    private static bool IsPng(byte[] bytes)
    {
        return bytes.Length >= 8 && bytes[0] == 0x89 && bytes[1] == 0x50 &&
               bytes[2] == 0x4E && bytes[3] == 0x47 && bytes[4] == 0x0D &&
               bytes[5] == 0x0A && bytes[6] == 0x1A && bytes[7] == 0x0A;
    }

    private static bool IsGif(byte[] bytes)
    {
        return bytes.Length >= 3 && bytes[0] == 0x47 && bytes[1] == 0x49 && bytes[2] == 0x46;
    }

    private static bool IsWebp(byte[] bytes)
    {
        return bytes.Length >= 12 && bytes[8] == 'W' && bytes[9] == 'E' &&
               bytes[10] == 'B' && bytes[11] == 'P';
    }

    private static bool IsZip(byte[] bytes)
    {
        return bytes.Length >= 4 && bytes[0] == 0x50 && bytes[1] == 0x4B &&
               bytes[2] == 0x03 && bytes[3] == 0x04;
    }

    private static bool Is7z(byte[] bytes)
    {
        return bytes.Length >= 6 && bytes[0] == 0x37 && bytes[1] == 0x7A &&
               bytes[2] == 0xBC && bytes[3] == 0xAF && bytes[4] == 0x27 &&
               bytes[5] == 0x1C;
    }

    private static bool IsRar(byte[] bytes)
    {
        return bytes.Length >= 7 && bytes[0] == 0x52 && bytes[1] == 0x61 &&
               bytes[2] == 0x72 && bytes[3] == 0x21 && bytes[4] == 0x1A &&
               bytes[5] == 0x07 && bytes[6] == 0x00;
    }

    private static bool IsTxt(byte[] bytes)
    {
        return bytes.Length >= 1 && IsPrintableAscii(bytes[0]);
    }

    private static bool IsCss(byte[] bytes)
    {
        return bytes.Length >= 4 && bytes[0] == 0x43 && bytes[1] == 0x53 &&
               bytes[2] == 0x53 && bytes[3] == 0x00;
    }

    // 辅助方法：判断一个字节是否为ASCII可打印字符
    private static bool IsPrintableAscii(byte b)
    {
        return b >= 0x20 && b <= 0x7E;
    }


    /// <summary>
    ///     图片压缩方法
    /// </summary>
    /// <param name="uploadConfig">上传配置对象，包含是否进行图片压缩等配置信息</param>
    /// <param name="uploadResult">上传结果对象，包含上传后的文件信息，如文件扩展名、新文件名等</param>
    private static void ImgCompress(WebUploadConfig uploadConfig, WebUploadResult uploadResult)
    {
        try
        {
            // 如果配置中设置不进行图片压缩，则直接返回
            if (uploadConfig.IsOriginalImageCompression == false) return;
            //验证图片扩展名否是在设置的原图压缩的扩展名集合中，如果不在，则直接返回
            if (!uploadConfig.OriginalImageCompressionExtension?.Contains(uploadResult.Extension,
                    StringComparer.OrdinalIgnoreCase) ?? false) return;

            // 生成新的文件标识符FID
            var newfid = Guid.NewGuid().ToString("N");
            // 根据上传配置、文件扩展名和新的FID生成新的文件名
            var newfilename = GetFileNewName(uploadConfig, uploadResult.Extension, newfid);

            // 获取相对文件夹路径
            var relFileFloder = GetRelFileFloder(uploadConfig);
            // 获取相对文件路径
            var relFileName = GetRelFileName(uploadConfig, relFileFloder, newfilename);
            // 根据上传配置和相对文件路径获取完整文件路径
            var fullFilePath = GetFullFilePath(uploadConfig, relFileName);

            // 使用SkiaSharp库对图片进行压缩
            SkiaSharpHelper.Compress(uploadResult.FullNewFilePath, fullFilePath, 0,
                uploadConfig.OriginalImageCompressionRatio);

            // 尝试删除原图文件
            var isDelete = FileHelper.TryDeleteFile(uploadResult.FullNewFilePath);


            //读取新文件信息，获取文件大小
            var newfileinfo = FileHelper.ReadFileInfo(fullFilePath);
            if (newfileinfo != null)
            {
                // 更新上传结果对象，设置新的文件标识符、新文件名和完整的新文件路径
                uploadResult.FId = newfid;
                uploadResult.NewFilename = newfilename;
                uploadResult.RelFileFloder = relFileFloder;
                uploadResult.RelFilePath = relFileName;
                uploadResult.FullNewFilePath = fullFilePath;

                uploadResult.FileSize_Byte = newfileinfo.Length;
                uploadResult.FileSize_MB = ByteSizeFormatter
                    .FormatBytes(uploadResult.FileSize_Byte, ByteUnit.MB, 1);
            }
        }
        catch (Exception ex)
        {
            // 记录异常信息，这里使用Console.WriteLine作为示例，实际应用中应使用日志框架
            Console.WriteLine($"An error occurred: {ex.Message}");
        }
    }

    /// <summary>
    ///     生成图片缩略图
    /// </summary>
    /// <param name="uploadConfig">上传配置，包含是否生成缩略图以及缩略图的宽度等设置</param>
    /// <param name="uploadResult">上传结果，包含完整的新文件路径，新文件名，以及缩略图文件名等信息</param>
    private static void ImgThumbnail(WebUploadConfig uploadConfig, WebUploadResult uploadResult)
    {
        try
        {
            // 检查是否需要生成缩略图并且文件是否存在
            if (!uploadConfig.IsImgThumbnail || !FileHelper.IsExistFile(uploadResult.FullNewFilePath)) return;
            //图片生成缩略图扩展名集合，在集合中的扩展名才会生成缩略图
            if (!uploadConfig.ImgThumbnailExtension?.Contains(uploadResult.Extension,
                    StringComparer.OrdinalIgnoreCase) ?? false) return;

            var fileinfo = FileHelper.ReadFileInfo(uploadResult.FullNewFilePath);

            // 创建缩略图文件名
            var thumbnailFileName = uploadResult.NewFilename.RemoveLastStr(uploadResult.Extension) +
                                    $"_thumbnail{uploadResult.Extension}";

            // 计算缩略图的完整路径
            var thumbnailNewfilepath2 = FileHelper.GetDirectoryFromFilePath(uploadResult.FullNewFilePath) +
                                         Path.DirectorySeparatorChar + thumbnailFileName;

            // 使用SkiaSharp库压缩并切割图片，生成缩略图
            SkiaSharpHelper.CompressAndCut(uploadResult.FullNewFilePath, thumbnailNewfilepath2,
                uploadConfig.ImgThumbnailWith, 0, 0, 30);

            // 设置生成的缩略图文件名
            uploadResult.ThumbnailFileName = thumbnailFileName;
            // 转换为相对路径
            uploadResult.ThumbnailRelFileName =
                GetRelFileName(uploadConfig, uploadResult.RelFileFloder, thumbnailFileName);
        }
        catch (Exception ex)
        {
            // 异常处理，当前为空，应记录或处理异常
        }
    }

    /// <summary>
    ///     根据上传配置生成文件名称。
    /// </summary>
    /// <param name="uploadConfig">上传的配置</param>
    /// <param name="extension">上传的文件扩展</param>
    /// <param name="fid">文件ID</param>
    private static string GetFileNewName(WebUploadConfig uploadConfig, string extension, string fid)
    {
        //使用原子递增计数器
        //为每个文件名添加一个基于原子递增计数器的唯一标识符。这样即使在同一时刻有多个线程生成文件名，由于计数器是原子操作，也不会出现重复的情况
        //Interlocked.Increment(ref _counter);
        var baseFileName = "";
        // 如果客户没有指定文件名，则自动生成文件名
        if (string.IsNullOrWhiteSpace(uploadConfig.CustomerFileName))
            //baseFileName = $"{fid}";
            return fid;
        else
        {
            // 如果客户指定了文件名，检查是否已包含扩展名
            if (uploadConfig.CustomerFileName.ToLower().EndsWith(extension.ToLower()))
                baseFileName = $"{uploadConfig.CustomerFileName.RemoveLastStr(extension)}";
            else
                // 如果自定义文件名不包含扩展名，则在末尾添加扩展名
                baseFileName = $"{uploadConfig.CustomerFileName}";
        }

        // // 如果设置了更改扩展名，则加上新文件名中的扩展名
        // if (uploadConfig.IsChangeExtensionName)
        // {
        //     uploadResult.NewFilename =$"{uploadResult.NewFilename}{uploadConfig.ChangeExtensionName}}" ;
        // }

        return $"{baseFileName}{extension}".ToLower();
        ;
    }


    // /// <summary>
    // /// 获取相对路径+文件名
    // /// </summary>
    // /// <param name="uploadConfig">上传配置，包含上传相关的设置信息。</param>
    // /// <param name="uploadResult">上传结果，用于存储上传操作的结果信息。</param>
    // private static void GetRelFileName(WebUploadConfig uploadConfig, WebUploadResult uploadResult)
    // {
    //    
    //     // 根据上传配置和新文件名，计算并设置上传结果的相对文件路径
    //     uploadResult.RelFilePath = GetRelFileName(uploadConfig, uploadResult.NewFilename);
    // }


    /// <summary>
    ///     获取相对路径+文件名
    /// </summary>
    /// <param name="uploadConfig"></param>
    /// <param name="relFileFloder">相对文件夹路径:例如：files\\2023\\01\\01\\</param>
    /// <param name="fileName">文件名：例如：111.png</param>
    /// <returns></returns>
    private static string GetRelFileName(WebUploadConfig uploadConfig, string relFileFloder, string fileName)
    {
        return $"{relFileFloder?.Trim('\\') ?? ""}\\{fileName?.TrimStart('\\') ?? ""}".ToOsDirectory();
    }

    /// <summary>
    ///     获取相对文件夹路径
    /// </summary>
    /// <param name="uploadConfig"></param>
    /// <returns></returns>
    private static string GetRelFileFloder(WebUploadConfig uploadConfig)
    {
        var confiRelFileFloder = uploadConfig.RelFileFloder?.TrimEnd('\\') ?? "";
        var relFileFloder = uploadConfig.DatetimeFloderType switch
        {
            WebUploadDatetimeFloderType.无日期文件夹 =>
                $"{confiRelFileFloder}",
            WebUploadDatetimeFloderType.年文件夹 =>
                $"{confiRelFileFloder}\\{DateTime.Now:yyyy}",
            WebUploadDatetimeFloderType.年月文件夹 =>
                $"{confiRelFileFloder}\\{DateTime.Now:yyyyMM}",
            WebUploadDatetimeFloderType.年月日文件夹 =>
                $"{confiRelFileFloder}\\{DateTime.Now:yyyyMMdd}",
            _ => $"{confiRelFileFloder}"
        };
        return relFileFloder.ToOsDirectory();
    }


    /// <summary>
    ///     获取上传文件的完整路径。
    /// </summary>
    /// <param name="uploadConfig">上传配置对象，包含上传的根路径等配置信息。</param>
    /// <param name="relFilePath">相对路径+文件名：例如：files\\2023\\01\\01\\1111.png</param>
    private static string GetFullFilePath(WebUploadConfig uploadConfig, string relFilePath)
    {
        if (string.IsNullOrWhiteSpace(uploadConfig.UploadFloder))
            // 如果根路径未设置，则获取默认的文件上传文件夹
            uploadConfig.UploadFloder = GetFileUploadFloder();

        // 拼接生成新文件的完整路径
        var fullNewFilePath = uploadConfig.UploadFloder + Path.DirectorySeparatorChar + relFilePath;
        //根据文件的绝对路径创建文件夹
        FileHelper.CreateDirectoryByFilePath(fullNewFilePath);

        return fullNewFilePath.ToOsDirectory();
    }

    /// <summary>
    ///     处理路径或url地址
    /// </summary>
    /// <param name="str"></param>
    /// <param name="replaceCount">替换次数，默认5次</param>
    /// <returns></returns>
    private static string HandlePathOrUrl(string str, int replaceCount = 5)
    {
        for (var i = 0; i < replaceCount; i++) str = str.Replace("\\\\", "/").Replace("\\", "/").Replace("//", "/");
        return str.ToOsDirectory();
    }

    /// <summary>
    ///     获取上传文件的文件夹路径。
    /// </summary>
    /// <returns>返回上传文件的文件夹的物理路径。</returns>
    public static string GetFileUploadFloder()
    {
        // 获取配置中指定的上传文件根路径
        var defaultPhysicalPath = App.Configuration["AbcWebUploadSetting:UploadFloder"];
        if (string.IsNullOrWhiteSpace(defaultPhysicalPath))
        {
            // 如果配置中不存在或路径无效，尝试使用默认的物理路径（网站内容根目录下的upload文件夹）
            if (App.WebHostEnvironment != null)
                defaultPhysicalPath = $"{App.WebHostEnvironment.ContentRootPath.TrimEnd('\\')}\\uploads";
            else if (App.HostEnvironment != null)
                defaultPhysicalPath = $"{App.HostEnvironment.ContentRootPath.TrimEnd('\\')}\\uploads";
            else
                // 如果无法获取环境信息，则抛出异常
                //throw Oops.Bah("WebHostEnvironment 和 HostEnvironment 都为空了");
            {
                //判断当前语种代码
                if (GetSelectCultureCode == "en-US") throw Oops.Bah("Failed to get upload folder");

                throw Oops.Bah(L.Text["获取上传文件夹失败"]);
            }
        }
        else
        {
            if (!Directory.Exists(defaultPhysicalPath)) Directory.CreateDirectory(defaultPhysicalPath);
        }

        return defaultPhysicalPath.ToOsDirectory();
    }
}